package com.office.system.service.impl;

import com.office.common.utils.SensitiveWordUtil;
import com.office.system.service.IDataCleaningService;
import com.office.system.service.ISysOssService;
import com.office.system.domain.vo.SysOssVo;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.beans.factory.annotation.Autowired;

import jakarta.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.regex.Pattern;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import java.io.File;
import java.io.FileOutputStream;

/**
 * 数据清洗服务
 *
 * @author 数字牧马人
 */

@Service
public class DataCleaningServiceImpl implements IDataCleaningService {

    @Autowired
    private ISysOssService sysOssService;

    private static final int MAX_ERRORS = 10;
    private static final Pattern SPECIAL_CHAR_PATTERN = Pattern.compile("[^\\w\\s\\u4e00-\\u9fa5@.]");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Za-z0-9+_.-]+@(.+)$");
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Set<String> COMMON_ENCODINGS = new HashSet<>(Arrays.asList(
        "UTF-8", "GBK", "GB2312", "ISO-8859-1", "UTF-16"
    ));

    @PostConstruct
    public void init() {
        // 初始化敏感词库
        SensitiveWordUtil.init();
    }

    @Override
    public Map<String, Object> cleanData(MultipartFile file) throws IOException {
        Map<String, Object> result = new HashMap<>();
        List<String> errors = new ArrayList<>();
        List<String> cleanedData = new ArrayList<>();

        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            result.put("status", "error");
            result.put("message", "上传的文件不能为空");
            return result;
        }

        // 检查文件大小
        if (file.getSize() == 0) {
            result.put("status", "error");
            result.put("message", "上传的文件大小为0字节");
            return result;
        }

        String fileName = file.getOriginalFilename();
        if (fileName == null || fileName.isEmpty()) {
            result.put("status", "error");
            result.put("message", "文件名不能为空");
            return result;
        }

        String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

        // 如果是PDF文件，直接返回原始内容
        if ("pdf".equals(fileExtension)) {
            try {
                byte[] fileBytes = file.getBytes();
                String base64Pdf = Base64.getEncoder().encodeToString(fileBytes);
                cleanedData.add(base64Pdf);
                result.put("status", "success");
                result.put("message", "PDF文件处理成功");
                result.put("cleanedData", cleanedData);
                return result;
            } catch (Exception e) {
                result.put("status", "error");
                result.put("message", "PDF文件处理失败：" + e.getMessage());
                return result;
            }
        }

        // 如果是Word文件，进行清洗处理
        if ("docx".equals(fileExtension) || "doc".equals(fileExtension)) {
            try {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                performDataCleaning(file, cleanedData, outputStream);
                byte[] cleanedBytes = outputStream.toByteArray();
                String base64Word = Base64.getEncoder().encodeToString(cleanedBytes);
                cleanedData.add(base64Word);
                result.put("status", "success");
                result.put("message", "Word文件清洗成功");
                result.put("cleanedData", cleanedData);
                return result;
            } catch (Exception e) {
                result.put("status", "error");
                result.put("message", "Word文件清洗失败：" + e.getMessage());
                return result;
            }
        }

        try {
            result.put("status", "processing");
            result.put("message", "正在分析文件...");
            try (InputStream inputStream = file.getInputStream()) {
                checkFileEncoding(inputStream, errors);
            }
            result.put("status", "processing");
            result.put("message", "正在清洗数据...");
            performDataCleaning(file, cleanedData, null);
            if (errors.size() > MAX_ERRORS) {
                result.put("status", "error");
                result.put("message", "数据文件中的错误数量过多，建议重新采集或提供正确格式的文件");
                result.put("errors", errors);
            } else {
                result.put("status", "success");
                result.put("message", "文件清洗成功");
                result.put("errors", errors);
                result.put("cleanedData", cleanedData);
                String cleanedContent = String.join("\n", cleanedData);
                result.put("cleanedBytes", cleanedContent.getBytes());
            }
            return result;
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "文件处理失败：" + e.getMessage());
            return result;
        }
    }

    // 修改performDataCleaning方法，支持输出流
    private void performDataCleaning(MultipartFile file, List<String> cleanedData, ByteArrayOutputStream outputStream) throws IOException {
        try (InputStream inputStream = file.getInputStream()) {
            String fileName = file.getOriginalFilename();
            String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

            switch (fileExtension) {
                case "xlsx":
                case "xls":
                    cleanExcelData(inputStream, cleanedData, outputStream);
                    break;
                case "docx":
                case "doc":
                    cleanWordData(inputStream, cleanedData, fileName, outputStream);
                    break;
                case "txt":
                    cleanTextData(inputStream, cleanedData);
                    break;
                case "csv":
                    cleanCsvData(inputStream, cleanedData);
                    break;
                case "md":
                    cleanMarkdownData(inputStream, cleanedData);
                    break;
            }
        }
    }

    // 修改cleanWordData方法，支持输出流
    private void cleanWordData(InputStream inputStream, List<String> cleanedData, String originalFileName, ByteArrayOutputStream outputStream) throws IOException {
        XWPFDocument document = new XWPFDocument(inputStream);
        XWPFDocument newDocument = new XWPFDocument();
        try {
            // 复制所有段落，包括图片和格式
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                XWPFParagraph newParagraph = newDocument.createParagraph();
                newParagraph.getCTP().setPPr(paragraph.getCTP().getPPr()); // 复制段落属性
                for (XWPFRun run : paragraph.getRuns()) {
                    XWPFRun newRun = newParagraph.createRun();
                    newRun.getCTR().setRPr(run.getCTR().getRPr());
                    if (run.getEmbeddedPictures() != null && !run.getEmbeddedPictures().isEmpty()) {
                        for (XWPFPicture pic : run.getEmbeddedPictures()) {
                            XWPFPictureData picData = pic.getPictureData();
                            if (picData != null) {
                                try (ByteArrayInputStream picStream = new ByteArrayInputStream(picData.getData())) {
                                    newRun.addPicture(
                                        picStream,
                                        picData.getPictureType(),
                                        picData.getFileName(),
                                        (int) pic.getCTPicture().getSpPr().getXfrm().getExt().getCx(),
                                        (int) pic.getCTPicture().getSpPr().getXfrm().getExt().getCy()
                                    );
                                } catch (Exception e) {
                                    // 图片复制失败，跳过该图片
                                }
                            }
                        }
                    }
                    String text = run.getText(0);
                    if (text != null) {
                        text = SensitiveWordUtil.replaceSensitiveWords(text, 1, "*");
                        newRun.setText(text, 0);
                    }
                }
            }
            for (XWPFTable table : document.getTables()) {
                XWPFTable newTable = newDocument.createTable();
                newTable.getCTTbl().setTblPr(table.getCTTbl().getTblPr());
                newTable.removeRow(0);
                for (XWPFTableRow row : table.getRows()) {
                    XWPFTableRow newRow = newTable.createRow();
                    for (int i = 0; i < row.getTableCells().size(); i++) {
                        XWPFTableCell cell = row.getCell(i);
                        XWPFTableCell newCell = newRow.getCell(i);
                        if (newCell == null) {
                            newCell = newRow.addNewTableCell();
                        }
                        newCell.getCTTc().setTcPr(cell.getCTTc().getTcPr());
                        newCell.removeParagraph(0);
                        for (XWPFParagraph para : cell.getParagraphs()) {
                            XWPFParagraph newPara = newCell.addParagraph();
                            newPara.getCTP().setPPr(para.getCTP().getPPr());
                            for (XWPFRun run : para.getRuns()) {
                                XWPFRun newRun = newPara.createRun();
                                newRun.getCTR().setRPr(run.getCTR().getRPr());
                                if (run.getEmbeddedPictures() != null && !run.getEmbeddedPictures().isEmpty()) {
                                    for (XWPFPicture pic : run.getEmbeddedPictures()) {
                                        XWPFPictureData picData = pic.getPictureData();
                                        if (picData != null) {
                                            try (ByteArrayInputStream picStream = new ByteArrayInputStream(picData.getData())) {
                                                newRun.addPicture(
                                                    picStream,
                                                    picData.getPictureType(),
                                                    picData.getFileName(),
                                                    (int) pic.getCTPicture().getSpPr().getXfrm().getExt().getCx(),
                                                    (int) pic.getCTPicture().getSpPr().getXfrm().getExt().getCy()
                                                );
                                            } catch (Exception e) {
                                                // 图片复制失败，跳过该图片
                                            }
                                        }
                                    }
                                }
                                String text = run.getText(0);
                                if (text != null) {
                                    text = SensitiveWordUtil.replaceSensitiveWords(text, 1, "*");
                                    newRun.setText(text, 0);
                                }
                            }
                        }
                    }
                }
            }
            newDocument.write(outputStream);
        } catch (Exception e) {
            throw new IOException("处理Word文档时发生错误: " + e.getMessage(), e);
        } finally {
            document.close();
            newDocument.close();
        }
    }

    // 修改cleanExcelData方法，支持输出流
    private void cleanExcelData(InputStream inputStream, List<String> cleanedData, ByteArrayOutputStream outputStream) throws IOException {
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);
        Workbook newWorkbook = new XSSFWorkbook();
        Sheet newSheet = newWorkbook.createSheet();
        Set<String> processedRows = new HashSet<>();
        int newRowIndex = 0;
        for (int i = 0; i < sheet.getLastRowNum() + 1; i++) {
            Row originalRow = sheet.getRow(i);
            if (originalRow != null) {
                StringBuilder rowContent = new StringBuilder();
                Map<Integer, String> cellValues = new HashMap<>();
                for (int j = 0; j < originalRow.getLastCellNum(); j++) {
                    Cell originalCell = originalRow.getCell(j);
                    if (originalCell != null) {
                        String value = getCellValueAsString(originalCell).trim();
                        cellValues.put(j, value);
                        rowContent.append(value).append("|");
                    }
                }
                String rowKey = rowContent.toString();
                if (!processedRows.contains(rowKey)) {
                    processedRows.add(rowKey);
                    Row newRow = newSheet.createRow(newRowIndex++);
                    for (Map.Entry<Integer, String> entry : cellValues.entrySet()) {
                        Cell newCell = newRow.createCell(entry.getKey());
                        newCell.setCellValue(entry.getValue());
                    }
                }
            }
        }
        newWorkbook.write(outputStream);
        byte[] excelBytes = outputStream.toByteArray();
        String base64Excel = Base64.getEncoder().encodeToString(excelBytes);
        cleanedData.add(base64Excel);
        workbook.close();
        newWorkbook.close();
    }

    private void cleanTextData(InputStream inputStream, List<String> cleanedData) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        Set<String> processedLines = new HashSet<>(); // 用于去重
        Set<String> processedNames = new HashSet<>(); // 用于去重姓名
        Set<String> processedPhones = new HashSet<>(); // 用于去重电话
        Set<String> processedEmails = new HashSet<>(); // 用于去重邮箱

        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (line.isEmpty()) continue;

            // 标准化分隔符
            line = line.replaceAll("[：:！!]", ":");

            // 标准化电话号码格式（移除所有空格）
            line = line.replaceAll("(\\d{3})\\s*(\\d{4})\\s*(\\d{4})", "$1$2$3");

            // 处理邮箱格式
            // 1. 先处理_AT_格式
            line = line.replaceAll("(\\w+)_AT_(\\w+\\.\\w+)", "$1@$2");
            // 2. 处理其他不规范的邮箱格式
            line = line.replaceAll("(\\w+)exampl\\.come\\.com", "$1@example.com");
            line = line.replaceAll("(\\w+)example\\.com", "$1@example.com");
            line = line.replaceAll("(\\w+)@(\\w+)@(\\w+)", "$1@$2.$3");

            // 处理没有字段名的行
            if (!line.contains("姓名:") && !line.contains("电话:") && !line.contains("邮箱:")) {
                // 使用正则表达式匹配并添加字段名
                line = line.replaceAll("(\\S+)\\s+(\\d{11})\\s+(\\S+@\\S+)\\s+(.+)",
                    "姓名:$1\n电话:$2\n邮箱:$3\n地址:$4");
                // 处理只有姓名、邮箱和地址的情况
                if (!line.contains("电话:")) {
                    line = line.replaceAll("(\\S+)\\s+(\\S+@\\S+)\\s+(.+)",
                        "姓名:$1\n邮箱:$2\n地址:$3");
                }
            }

            // 标准化字段名和分隔符
            line = line.replaceAll("(姓名|电话|邮箱|地址)[：:]*", "\n$1:");

            // 清理地址中的特殊字符和邮箱域名
            if (line.contains("地址:")) {
                String[] parts = line.split("地址:");
                if (parts.length > 1) {
                    String address = parts[1].trim();
                    // 修改特殊字符处理，保留@符号
                    address = address.replaceAll("[#!]", "").trim();
                    address = address.replaceAll("example\\.com", "").trim();
                    address = address.replaceAll("\\s+", " ").trim();
                    // 过滤敏感词
                    address = SensitiveWordUtil.replaceSensitiveWords(address, 1, "*");
                    line = parts[0] + "地址:" + address;
                }
            }

            // 清理其他特殊字符，但保留邮箱中的@符号
            line = line.replaceAll("(?<!\\w)@(?!\\w+\\.\\w+)", ""); // 只删除不在邮箱格式中的@符号

            // 标准化空格
            line = line.replaceAll("\\s+", " ");

            // 处理null值
            line = line.replaceAll("null", "");

            // 过滤敏感词
            line = SensitiveWordUtil.replaceSensitiveWords(line, 1, "*");

            // 提取关键信息用于去重
            String name = "";
            String phone = "";
            String email = "";

            if (line.contains("姓名:")) {
                String[] parts = line.split("姓名:");
                if (parts.length > 1) {
                    name = parts[1].trim().split("\\s+")[0];
                    // 检查是否是电话号码
                    if (name.matches("\\d{11}")) {
                        phone = name;
                        name = "";
                    }
                }
            }

            if (line.contains("电话:")) {
                String[] parts = line.split("电话:");
                if (parts.length > 1) {
                    phone = parts[1].trim().split("\\s+")[0];
                }
            }

            if (line.contains("邮箱:")) {
                String[] parts = line.split("邮箱:");
                if (parts.length > 1) {
                    email = parts[1].trim().split("\\s+")[0];
                }
            }

            // 去除重复数据（基于姓名、电话和邮箱的组合）
            boolean isDuplicate = false;
            if (!name.isEmpty() && processedNames.contains(name)) {
                isDuplicate = true;
            }
            if (!phone.isEmpty() && processedPhones.contains(phone)) {
                isDuplicate = true;
            }
            if (!email.isEmpty() && processedEmails.contains(email)) {
                isDuplicate = true;
            }

            if (!isDuplicate) {
                if (!name.isEmpty()) processedNames.add(name);
                if (!phone.isEmpty()) processedPhones.add(phone);
                if (!email.isEmpty()) processedEmails.add(email);
                processedLines.add(line);
                cleanedData.add(line);
            }
        }
        scanner.close();
    }

    private void cleanCsvData(InputStream inputStream, List<String> cleanedData) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            String[] values = line.split(",");
            StringBuilder cleanedRow = new StringBuilder();

            for (String value : values) {
                value = value.trim();
                // 移除特殊字符
                value = SPECIAL_CHAR_PATTERN.matcher(value).replaceAll("");
                // 标准化空格
                value = value.replaceAll("\\s+", " ");
                cleanedRow.append(value).append("|");
            }

            cleanedData.add(cleanedRow.toString());
        }
        scanner.close();
    }

    private void cleanMarkdownData(InputStream inputStream, List<String> cleanedData) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            // 移除特殊字符，但保留Markdown语法字符
            line = line.replaceAll("[^\\w\\s\\u4e00-\\u9fa5#*`\\[\\]()\\-_]", "");
            // 标准化空格
            line = line.replaceAll("\\s+", " ");
            if (!line.isEmpty()) {
                cleanedData.add(line);
            }
        }
        scanner.close();
    }

    private void checkFileEncoding(InputStream inputStream, List<String> errors) throws IOException {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }
        byte[] bytes = result.toByteArray();

        boolean validEncoding = false;
        for (String encoding : COMMON_ENCODINGS) {
            try {
                String content = new String(bytes, encoding);
                if (isValidEncoding(content)) {
                    validEncoding = true;
                    break;
                }
            } catch (Exception ignored) {
            }
        }

        if (!validEncoding) {
            errors.add("文件编码格式可能存在问题，建议使用UTF-8或GBK编码");
        }
    }

    private boolean isValidEncoding(String content) {
        return !content.contains("") && !content.contains("?");
    }

    private void cleanExcelFile(InputStream inputStream, List<String> errors) throws IOException {
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);

        // 检查表头
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            errors.add("Excel文件缺少表头");
            return;
        }

        // 检查表头格式
        for (int i = 0; i < headerRow.getLastCellNum(); i++) {
            Cell cell = headerRow.getCell(i);
            if (cell != null) {
                String headerValue = cell.getStringCellValue().trim();
                if (headerValue.isEmpty()) {
                    errors.add("表头第" + (i + 1) + "列为空");
                }
                if (SPECIAL_CHAR_PATTERN.matcher(headerValue).find()) {
                    errors.add("表头第" + (i + 1) + "列包含特殊字符");
                }
            }
        }

        // 检查数据完整性
        Set<String> duplicateRows = new HashSet<>();
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                errors.add("第" + (i + 1) + "行为空");
                continue;
            }

            StringBuilder rowContent = new StringBuilder();
            boolean hasEmptyCell = false;
            boolean hasInvalidData = false;

            // 检查每列的数据
            for (int j = 0; j < headerRow.getLastCellNum(); j++) {
                Cell cell = row.getCell(j);
                if (cell == null) {
                    errors.add("第" + (i + 1) + "行第" + (j + 1) + "列数据为空");
                    hasEmptyCell = true;
                    continue;
                }

                String cellValue = getCellValueAsString(cell).trim();
                rowContent.append(cellValue).append("|");

                // 检查特殊字符
                if (SPECIAL_CHAR_PATTERN.matcher(cellValue).find()) {
                    errors.add("第" + (i + 1) + "行第" + (j + 1) + "列包含特殊字符");
                    hasInvalidData = true;
                }

                // 检查邮箱格式
                if (cellValue.contains("@") && !EMAIL_PATTERN.matcher(cellValue).matches()) {
                    errors.add("第" + (i + 1) + "行第" + (j + 1) + "列邮箱格式不正确");
                    hasInvalidData = true;
                }

                // 检查手机号格式
                if (cellValue.length() == 11 && !PHONE_PATTERN.matcher(cellValue).matches()) {
                    errors.add("第" + (i + 1) + "行第" + (j + 1) + "列手机号格式不正确");
                    hasInvalidData = true;
                }
            }

            // 检查重复行
            String rowStr = rowContent.toString();
            if (!duplicateRows.add(rowStr)) {
                errors.add("第" + (i + 1) + "行数据重复");
            }

            // 检查数据一致性
            if (hasEmptyCell && hasInvalidData) {
                errors.add("第" + (i + 1) + "行数据质量较差，存在空值和无效数据");
            }
        }

        workbook.close();
    }

    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                }
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    private void cleanWordFile(InputStream inputStream, List<String> errors) throws IOException {
        XWPFDocument document = new XWPFDocument(inputStream);

        // 检查文档是否为空
        if (document.getParagraphs().isEmpty()) {
            errors.add("Word文档为空");
        }

        // 检查段落格式和内容
        Set<String> duplicateParagraphs = new HashSet<>();
        document.getParagraphs().forEach(paragraph -> {
            String text = paragraph.getText().trim();

            if (text.isEmpty()) {
                errors.add("存在空段落");
                return;
            }

            // 检查特殊字符
            if (SPECIAL_CHAR_PATTERN.matcher(text).find()) {
                errors.add("段落包含特殊字符: " + text.substring(0, Math.min(20, text.length())));
            }

            // 检查重复段落
            if (!duplicateParagraphs.add(text)) {
                errors.add("存在重复段落: " + text.substring(0, Math.min(20, text.length())));
            }

            // 检查段落格式
            if (text.length() > 0 && text.charAt(0) == ' ') {
                errors.add("段落开头存在多余空格");
            }
            if (text.length() > 0 && text.charAt(text.length() - 1) == ' ') {
                errors.add("段落结尾存在多余空格");
            }
        });

        document.close();
    }

    private void cleanTextFile(InputStream inputStream, List<String> errors) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        int lineNumber = 0;
        Set<String> duplicateLines = new HashSet<>();

        while (scanner.hasNextLine()) {
            lineNumber++;
            String line = scanner.nextLine();
            String trimmedLine = line.trim();

            if (trimmedLine.isEmpty()) {
                errors.add("第" + lineNumber + "行为空行");
                continue;
            }

            // 检查特殊字符
            if (SPECIAL_CHAR_PATTERN.matcher(trimmedLine).find()) {
                errors.add("第" + lineNumber + "行包含特殊字符");
            }

            // 检查重复行
            if (!duplicateLines.add(trimmedLine)) {
                errors.add("第" + lineNumber + "行内容重复");
            }

            // 检查行首尾空格
            if (line.length() > trimmedLine.length()) {
                errors.add("第" + lineNumber + "行存在多余空格");
            }
        }

        scanner.close();
    }

    private void cleanCsvFile(InputStream inputStream, List<String> errors) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        int lineNumber = 0;
        Set<String> duplicateRows = new HashSet<>();
        int expectedColumns = -1;

        while (scanner.hasNextLine()) {
            lineNumber++;
            String line = scanner.nextLine();
            String[] values = line.split(",");

            // 检查每行的列数是否一致
            if (lineNumber == 1) {
                // 第一行作为表头
                if (values.length == 0) {
                    errors.add("CSV文件缺少表头");
                    return;
                }
                expectedColumns = values.length;

                // 检查表头格式
                for (int i = 0; i < values.length; i++) {
                    String header = values[i].trim();
                    if (header.isEmpty()) {
                        errors.add("表头第" + (i + 1) + "列为空");
                    }
                    if (SPECIAL_CHAR_PATTERN.matcher(header).find()) {
                        errors.add("表头第" + (i + 1) + "列包含特殊字符");
                    }
                }
            } else {
                // 检查数据行
                if (values.length == 0) {
                    errors.add("第" + lineNumber + "行为空");
                    continue;
                }

                if (values.length != expectedColumns) {
                    errors.add("第" + lineNumber + "行列数与表头不一致");
                }

                // 检查每列数据
                StringBuilder rowContent = new StringBuilder();
                for (int i = 0; i < values.length; i++) {
                    String value = values[i].trim();
                    rowContent.append(value).append("|");

                    if (value.isEmpty()) {
                        errors.add("第" + lineNumber + "行第" + (i + 1) + "列数据为空");
                    }

                    if (SPECIAL_CHAR_PATTERN.matcher(value).find()) {
                        errors.add("第" + lineNumber + "行第" + (i + 1) + "列包含特殊字符");
                    }
                }

                // 检查重复行
                String rowStr = rowContent.toString();
                if (!duplicateRows.add(rowStr)) {
                    errors.add("第" + lineNumber + "行数据重复");
                }
            }
        }

        scanner.close();
    }

    private void cleanMarkdownFile(InputStream inputStream, List<String> errors) throws IOException {
        Scanner scanner = new Scanner(inputStream);
        int lineNumber = 0;
        boolean hasContent = false;
        Set<String> duplicateLines = new HashSet<>();

        while (scanner.hasNextLine()) {
            lineNumber++;
            String line = scanner.nextLine();
            String trimmedLine = line.trim();

            if (!trimmedLine.isEmpty()) {
                hasContent = true;

                // 检查特殊字符
                if (SPECIAL_CHAR_PATTERN.matcher(trimmedLine).find()) {
                    errors.add("第" + lineNumber + "行包含特殊字符");
                }

                // 检查重复行
                if (!duplicateLines.add(trimmedLine)) {
                    errors.add("第" + lineNumber + "行内容重复");
                }

                // 检查Markdown语法
                if (trimmedLine.startsWith("#")) {
                    if (!trimmedLine.matches("^#{1,6}\\s.+")) {
                        errors.add("第" + lineNumber + "行标题格式不正确");
                    }
                }

                // 检查链接格式
                if (trimmedLine.contains("](") && !trimmedLine.matches(".*\\[.+\\]\\(.+\\)")) {
                    errors.add("第" + lineNumber + "行链接格式不正确");
                }
            }
        }

        if (!hasContent) {
            errors.add("Markdown文件为空");
        }

        scanner.close();
    }

    // 自定义MultipartFile实现，避免依赖spring-test
    private static class SimpleMultipartFile implements MultipartFile {
        private final String name;
        private final String originalFilename;
        private final String contentType;
        private final byte[] content;

        public SimpleMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
            this.name = name;
            this.originalFilename = originalFilename;
            this.contentType = contentType;
            this.content = content;
        }

        @Override public String getName() { return name; }
        @Override public String getOriginalFilename() { return originalFilename; }
        @Override public String getContentType() { return contentType; }
        @Override public boolean isEmpty() { return content == null || content.length == 0; }
        @Override public long getSize() { return content.length; }
        @Override public byte[] getBytes() { return content; }
        @Override public InputStream getInputStream() { return new ByteArrayInputStream(content); }
        @Override public void transferTo(File dest) throws IOException, IllegalStateException {
            try (FileOutputStream fos = new FileOutputStream(dest)) {
                fos.write(content);
            }
        }
    }
}
